import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
import 'package:http_parser/http_parser.dart';
import 'package:leader_doctor_flutter/plugins/plugins_messages.g.dart';

import '../data/app.dart';
import '../utils/log_utils.dart';
import '../utils/rest_utils.dart';
import '../utils/string_utils.dart';
import 'header.dart';

enum NetErrorType {
  none,
  disconnected,
  timedOut,
  denied,
}

enum MethodType { get, post, put, patch, delete, head }

typedef IORequest = Future<http.Response> Function();

String commResponseMsg = ' 服务器打盹了 请稍后再试 ';

class HttpClient {
  /// get 方式请求
  static Future<HttpResponse> get(HttpRequest request) async {
    await request.initParams();
    return await _request(() async {
      return await App.instance.client.get(request.realUri!, headers: request.realHeaders);
    });
  }

  /// post 方式
  /// content-type:x-www-form-urlencoded
  static Future<HttpResponse> post(HttpRequest request) async {
    await request.initParams();
    return await _request(() async {
      return await App.instance.client.post(request.realUri!, headers: request.realHeaders, body: request.body);
    });
  }

  /// post json 提交方式
  /// content-type:application/json
  static Future<HttpResponse> postJson(HttpRequest request) async {
    var headList = request.headers ?? {};
    headList['content-type'] = 'application/json';
    var json = request.body != null ? jsonEncode(request.body) : null;
    return post(request
      ..headers = headList
      ..body = json);
  }

  /// post 上传文件
  ///可上传多个文件 files
  static Future<HttpResponse> postFileBytes(HttpRequest httpRequest) async {
    await httpRequest.initParams();
    var request = http.MultipartRequest('POST', httpRequest.realUri!);
    request.headers.addAll(httpRequest.realHeaders!);
    httpRequest.files?.forEach((file) {
      request.files.add(http.MultipartFile.fromBytes('file', file?.bytes?.toList() ?? [],
          filename: file?.fileName, contentType: MediaType('application', 'octet-stream')));
    });
    return await _request(() async {
      return await Response.fromStream(await App.instance.client.send(request));
    });
  }

  static Future<HttpResponse> _request(IORequest request) async {
    http.Response response;
    try {
      response = await request();
    } on Exception catch (e) {
      Log.i('Network call failed: ${e.toString()}');
      response = http.Response('ERROR: Could not get a response', 404);
    }
    EasyLoading.dismiss();
    return HttpResponse(response);
  }
}

class HttpRequest {
  String url;
  Map<String, String>? headers;
  Map<String, dynamic>? urlParams;
  List<FileInfo?>? files;
  Object? body;
  bool isShowLoading = true;
  String? loadingStr;

  Uri? realUri;
  Map<String, String>? realHeaders;

  HttpRequest(this.url,
      {this.headers, this.urlParams, this.body, this.isShowLoading = true, this.loadingStr, this.files});

  initParams() async {
    //加载loading
    if (isShowLoading) {
      EasyLoading.show(
        status: loadingStr ?? '加载中...',
        maskType: EasyLoadingMaskType.clear,
      );
    }

    realHeaders = CommentHeader.header(headers);
    var baseUrl = App.instance.baseUrl ?? '';
    assert(baseUrl != '', 'baseUrl取值错误');
    //添加参数到url
    if (urlParams != null) {
      Map<String, String> params = {};
      urlParams?.forEach((key, value) {
        params[key] = value.toString();
      });
      //参数url编码
      url += RestUtils.encodeParams(params);
    }
    realUri = Uri.parse(baseUrl + url);

    printRequestParams(realUri, realHeaders, urlParams);
  }

  void printRequestParams(Uri? uri, Map<String, String>? header, Map<String, dynamic>? urlParams) {
    if (kDebugMode) {
      var msg = """
      ------------------------请求参数---------------------------
      url:$uri
      headers:$header
      urlParams:$urlParams
      body:$body
      ------------------------请求参数---------------------------
      """;
      Log.i(msg);
    }
  }
}

class HttpResponse {
  final http.Response? raw;

  NetErrorType? errorType;

  bool get success => errorType == NetErrorType.none;

  String? get body => raw?.body;

  Map<String, String>? get headers => raw?.headers;

  int get statusCode => raw?.statusCode ?? -1;

  HttpResponse(this.raw) {
    //No response at all, there must have been a connection error
    if (raw == null) {
      errorType = NetErrorType.disconnected;
    } else if (raw!.statusCode >= 200 && raw!.statusCode <= 299) {
      errorType = NetErrorType.none;
    } else if (raw!.statusCode >= 500 && raw!.statusCode < 600) {
      errorType = NetErrorType.timedOut;
    } else if (raw!.statusCode >= 400 && raw!.statusCode < 500) {
      errorType = NetErrorType.denied;
    }
  }
}

class ServiceResult<R> {
  final HttpResponse response;

  R? responseBody;
  int? responseCode;
  String? responseMsg;

  bool get parseError => responseBody == null;

  bool get success => response.success && responseCode == 0;

  /// responseBody 返回对象可以使用此方法解析
  /// 例：responseBody:{}
  ServiceResult(this.response, R? Function(Map<String, dynamic>) parser) {
    analysisData(parser);
  }

  /// responseBody 返回list可以使用此方法解析
  /// 例：responseBody:[{},{}]
  ServiceResult.list(this.response, R? Function(List<dynamic>?) parser) {
    analysisData(parser);
  }

  /// responseBody 返回对应值可以使用此方法解析
  /// 例：responseBody:"1"
  ServiceResult.simple(this.response) {
    analysisData(null);
  }

  analysisData(Function? parser) {
    if (StringUtils.isNotEmpty(response.body)) {
      try {
        //错误提示
        if (response.errorType == NetErrorType.disconnected) {
          Fluttertoast.showToast(msg: ' 连接异常，可能由于网络问题导致连接断开。请检查网络连接并重试 ');
        } else if (response.errorType == NetErrorType.timedOut) {
          Fluttertoast.showToast(msg: ' 请求超时，可能是服务器繁忙或网络不稳定所致。请稍后再试 ');
        } else if (response.errorType == NetErrorType.denied) {
          Fluttertoast.showToast(msg: commResponseMsg);
        } else if (response.success) {
          var json = jsonDecode(utf8.decode(response.raw!.bodyBytes));
          Log.i('返回值: $json');
          responseMsg = json['responseMsg'] as String?;
          responseCode = json['responseCode'] as int?;
          if (success) {
            responseBody = parser?.call(json['responseBody']) ?? json['responseBody'] as R;
          }
        } else {
          // if (StringUtils.isNotEmpty(responseMsg)) {
          //   Fluttertoast.showToast(msg: responseMsg ?? '');
          // } else {
          //   Fluttertoast.showToast(msg: commResponseMsg);
          // }
        }
      } on FormatException catch (e) {
        Log.i('ParseError: ${e.message}');
      }
    }
  }
}
